Что такое saga pattern и event sourcing в NestJS?

JuniorSaga Pattern и Event Sourcing в NestJS · Backend·Обновлено 17 сентября 2026
Коротко
Saga pattern — это способ управлять распределённой транзакцией через цепочку локальных шагов с компенсирующими действиями при ошибке, а Event Sourcing — способ хранить состояние приложения как последовательность событий, а не как текущий снимок данных. В NestJS оба паттерна реализуются с помощью модуля @nestjs/cqrs.

Saga Pattern

Saga — паттерн для управления распределёнными транзакциями, которые затрагивают несколько сервисов или агрегатов. Вместо одной большой ACID-транзакции процесс разбивается на последовательность локальных шагов, каждый из которых публикует событие после успешного выполнения. Если один из шагов завершается ошибкой, сага выполняет компенсирующие действия (compensating actions), отменяющие эффект уже выполненных шагов.

Ключевая идея: сага реагирует на события и решает, какую следующую команду отправить дальше.

Как это выглядит в NestJS

Модуль @nestjs/cqrs предоставляет декоратор @Saga(). Он позволяет описать сагу как RxJS-поток: сага подписывается на общий поток событий (Observable<IEvent>) и с помощью операторов filter/map превращает нужные события в новые команды.

Event Sourcing

Event Sourcing — подход к хранению состояния, при котором вместо текущего снимка данных (как в обычной таблице БД) хранится полная последовательность событий, приведших к этому состоянию. Текущее состояние агрегата восстанавливается путём последовательного применения всех событий (replay).

Преимущества:

  • полный аудит истории изменений состояния
  • возможность восстановить состояние на любой момент времени
  • естественная интеграция с CQRS и событийной архитектурой

Недостатки:

  • сложность реализации и отладки
  • необходимость версионирования событий при изменении схемы
  • дополнительные затраты на snapshot'ы для ускорения восстановления состояния при большой истории событий

Как это связано с NestJS

@nestjs/cqrs даёт базовые строительные блоки: EventBus, CommandBus, класс AggregateRoot с методом apply() для генерации событий и EventsHandler для их обработки. Важно понимать: сам модуль не хранит события в базе данных из коробки — он лишь предоставляет инфраструктуру публикации и обработки событий. Полноценный event store нужно подключать отдельно.

Как это работает вместе

Типичный сценарий: агрегат вызывает apply(), генерируя событие → событие публикуется через EventBus → сага подписана на этот поток и, увидев нужное событие, отправляет новую команду через CommandBus → обработчик команды выполняет следующий шаг бизнес-процесса.

Так распределённый процесс (например, оформление заказа: списание денег, резервирование товара, отправка уведомления) реализуется без единой транзакции — согласованность достигается за счёт цепочки событий и компенсирующих действий при сбоях.

Что хочет услышать интервьюер

Кандидат понимает, что saga решает проблему распределённых транзакций без двухфазного коммита

Кандидат знает про компенсирующие действия при ошибке в одном из шагов

Кандидат понимает разницу между хранением снимка состояния и хранением событий

Кандидат знает, что в NestJS для этого используется модуль @nestjs/cqrs (Saga, EventBus, CommandBus)

Кандидат может привести простой пример сценария (например, оформление заказа)

Пример: Пример саги в NestJS с @nestjs/cqrs

import { Injectable } from '@nestjs/common';
import { ICommand, ofType, Saga } from '@nestjs/cqrs';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { OrderCreatedEvent } from './events/order-created.event';
import { ReserveStockCommand } from './commands/reserve-stock.command';

@Injectable()
export class OrderSagas {
  // Сага подписывается на поток событий и реагирует на OrderCreatedEvent
  @Saga()
  orderCreated = (events$: Observable<any>): Observable<ICommand> => {
    return events$.pipe(
      ofType(OrderCreatedEvent),
      // при создании заказа инициируем резервирование товара на складе
      map((event) => new ReserveStockCommand(event.orderId, event.items)),
    );
  };
}

Типичные ошибки

Путают saga pattern с обычной БД-транзакцией и не упоминают компенсирующие действия

Считают, что @nestjs/cqrs сам хранит события в базе данных без дополнительной настройки

Не могут объяснить, зачем вообще нужен replay событий и как восстанавливается текущее состояние

Путают Event Sourcing с обычной публикацией доменных событий без сохранения истории

Не упоминают, что при большом количестве событий нужны snapshot'ы для производительности

Лучшие курсы по теме

изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажерыAI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Node.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Nest.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее